package org.dreamwork.jasmine2.engine;

import org.dreamwork.jasmine2.web.controls.Page;
import org.dreamwork.util.IDisposable;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;

/**
 * HTTP 上下文。
 *
 * <p>表示一个 HTTP 请求的上下文环境，以线程静态的方式提供了 J2EE HTTP 对象，包括：<ul>
 * <li>application - ServletContext 对象</li>
 * <li>session - HttpSession 对象</li>
 * <li>request - HttpServletRequest 对象</li>
 * <li>response - HttpServletResponse 对象</li>
 * <li>page - #org.dreamwork.jasmine2.web.controls.Page 对象</li>
 * </ul>
 *
 * <p>可以在任意一个 j2ee http 操作中使用该对象获取相关的 HTTP 对象，如：<pre><code>
 *  // 保证以下代码在一个 jasmine2 Page 中或 jasmine2 web control 中调用
 *  // ...
 *  HttpContext ctx = HttpContext.current ();
 *  ServletContext servletContext = ctx.getApplication ();
 *  // ...
 * </code></pre>
 *
 * <p>还可以在任意一个 jasmine2 Page 或 jasmine2 web control 中存取各个作用域中的资源，如<pre><code>
 *  // 保证以下代码在一个 jasmine2 Page 中或 jasmine2 web control 中调用
 *  // ...
 *  HttpContext ctx = HttpContext.current ();
 *  Object res1 = ctx.getAttribute ("resource name", HttpContext.SCOPE_PAGE);
 *  // ...
 *  Object res2 = ctx.findAttribute ("resource name 2");
 *  // ...
 *  Object obj = fetchObjectAnyway ();
 *  ctx.setAttribute ("obj name", obj);
 * Created by IntelliJ IDEA.
 * User: seth
 * Date: 2009-2-3
 * Time: 10:15:59
 */
public class HttpContext implements IDisposable {
    private Page page;
    private ServletContext application;
    private HttpServletRequest request;
    private HttpServletResponse response;
    private HttpSession session;
    private Browser browser;

    private Map<String, Object> attrs = new HashMap<String, Object> ();
    private static final String BROWSER_SESSION_KEY = "org.dreamwork.jasmine2.engine.HttpContext.browser";

    public static final int
            /** 页面作用域 */
            SCOPE_PAGE = 0,
            /** 请求作用域 */
            SCOPE_REQUEST = 1,
            /** http 会话作用域 */
            SCOPE_SESSION = 2,
            /** 应用程序作用域 */
            SCOPE_APPLICATION = 3;

    static ThreadLocal<HttpContext> threadLocal = new ThreadLocal<HttpContext> ();

    public static HttpContext current () {
        return threadLocal.get ();
    }

    HttpContext () {
        threadLocal.set (this);
    }

    /**
     * 获取 jasmine2 Page 对象
     * @return jasmine2 Page 对象
     */
    public Page getPage () {
        return page;
    }

    public void setPage (Page page) {
        this.page = page;
    }

    /**
     * 获取 ServletContext 对象
     * @return ServletContext 对象
     */
    public ServletContext getApplication () {
        return application;
    }

    void setApplication (ServletContext application) {
        this.application = application;
    }

    /**
     * 获取 HttpServletRequest 对象
     * @return HttpServletRequest 对象
     */
    public HttpServletRequest getRequest () {
        return request;
    }

    void setRequest (HttpServletRequest request) {
        this.request = request;
    }

    /**
     * 获取 HttpServletResponse 对象
     * @return HttpServletResponse 对象
     */
    public HttpServletResponse getResponse () {
        return response;
    }

    void setResponse (HttpServletResponse response) {
        this.response = response;
    }

    /**
     * 获取 HttpSession 对象
     * @return HttpSession 对象
     */
    public HttpSession getSession () {
        return session;
    }

    void setSession (HttpSession session) {
        this.session = session;
    }

    /**
     * 保存当前页面属性
     * @param key 属性名称
     * @param value 属性值
     */
    public void setAttribute (String key, Object value) {
        attrs.put (key, value);
    }

    /**
     * 获取当前页面中指定名称的属性
     * @param key 属性名
     * @return 属性值
     */
    public Object getAttribute (String key) {
        return attrs.get (key);
    }

    public void removeAttribute (String key) {
        attrs.remove (key);
    }

    public void clearAttributes () {
        attrs.clear ();
    }

    /**
     * 获取指定作用域中指定名称的属性
     * @param key 属性值
     * @param scope 指定作用域
     * @return 属性值
     */
    public Object getAttribute (String key, int scope) {
        switch (scope) {
            case SCOPE_PAGE : return getAttribute (key);
            case SCOPE_REQUEST : return request.getAttribute (key);
            case SCOPE_SESSION : return session.getAttribute (key);
            case SCOPE_APPLICATION : return application.getAttribute (key);
        }
        throw new IllegalArgumentException ("Invalid argument scope !");
    }

    /**
     * 在所用作用域中查找指定名称的属性，查询顺序为：SCOPE_PAGE > SCOPE_REQUEST > SCOPE_SESSION > SCOPE_APPLICATION
     * @param key 属性名
     * @return 属性值
     */
    public Object findAttribute (String key) {
        for (int i = 0; i <= 3; i ++ ) {
            try {
                Object obj = getAttribute (key, i);
                if (obj != null) return obj;
            } catch (IllegalArgumentException ignore) {

            }
        }
        return null;
    }

    public Browser getBrowser () {
        if (browser == null) {
            HttpSession session = request.getSession ();
            browser = (Browser) session.getAttribute (BROWSER_SESSION_KEY);
            if (browser == null) {
                browser = new Browser (request.getHeader ("user-agent"));
                session.setAttribute (BROWSER_SESSION_KEY, browser);
            }
        }
        return browser;
    }

    @Override
    public void dispose () throws Throwable {
        threadLocal.remove ();
    }
}